//
// Created by none98 on 2021/9/10.
//

#include <sys/socket.h>
#include <spdlog/spdlog.h>
#include <signal.h>
#include "TcpServer.h"
#include "Selector.h"
#include "Timer.h"
#include "TimerEventQueue.h"
#include "Acceptor.h"
#include "EventLoop.h"
#include "TcpConnection.h"
#include "TimeStamp.h"

TcpServer::TcpServer():
    loop(new EventLoop),
    keepAlive(false)
{

}
static void handlerForPipe(int sig){
    return ;
}

void TcpServer::Start(const std::string &address, int port)
{
    signal(SIGPIPE,&handlerForPipe);
    acceptor.reset(new Acceptor(address,port,loop.get()));
    acceptor->SetNewConnection(connectionCallBack);
    /*
     * acceptor set callback;
     * */
    acceptor->SetRegisterInServerCallBack(std::bind(&TcpServer::RegisterConnection,this,std::placeholders::_1));
    acceptor->SetCloseInServerCallBack((std::bind(&TcpServer::CloseConnection,this,std::placeholders::_1)));
    loop->SetTimeout(10); //10ms
    loop->StartLoop();
}

void TcpServer::RegisterConnection(TcpConnectionPtr connection) {
    if(keepAlive){
        int val =1 ;
        if(setsockopt(connection->GetFd(),SOL_SOCKET,SO_KEEPALIVE,&val,sizeof(val))==-1){
            spdlog::error("set socket:{} keep-alive option going wrong,{}",connection->GetFd(), strerror(errno));
        }
    }
    connection->SetOnMessage(msgCallBack);
    connection->SetOnClose(closeCallBack);
    connection->SetWriteComplete(writeCompleteCallBack);
    connection->SetEventLoop(loop.get());
    {
        std::unique_lock<std::mutex> lock(mapMutex);
        connectionMap[connection->GetFd()]=connection;
    }

}

void TcpServer::CloseConnection(TcpConnectionPtr connection) {
    std::unique_lock<std::mutex> lock(mapMutex);
    if(connectionMap.find(connection->GetFd())!=connectionMap.end()){
        connection->GetEventLoop()->CancelTimerByfd(connection->GetFd());
        connectionMap.erase(connection->GetFd());
    }
}

TcpServer::~TcpServer() {

}

long TcpServer::AddTimer(int hours, int minutes, int seconds, int milliSeconds, const TimerCallBack &callBack, bool isCycle)const{
    return loop->AddTimer(Timer(TimeStamp(hours,minutes,seconds,minutes),callBack,isCycle,-1));
}

int TcpServer::GetConnectionSize(){
    std::unique_lock<std::mutex> lock(mapMutex);
    return connectionMap.size();
}




